--
-- Author: shunguo.chen
-- Date: 2018-06-07 11:27:37
--
-- TheatreController
--

local TheatreView = import("..views.TheatreView")
-- local TheatreNpcView = import("..views.TheatreNpcView")

local fileName = string.getModeName(...)
local ClassRef = class(fileName, app.mvc.ControllerBase)

function ClassRef:ctor(data)
    self.super.ctor(self, data)
end

function ClassRef:init()
    self._model = app:getInst("TheatreModel")

    self._sessionResultMsg = nil --pve结果缓存

    self._isEnterMap = false -- 是否进入地图
    self._isInAction = false -- 在过场动画中

    self._resultCronId = nil -- 等待歌剧院结果的超时任务
end

function ClassRef:removeListeners()
    self.super.removeListeners(self)

end

function ClassRef:listEvent()
    return { 
        "onMapChanged",
        "onReconnectSuccessed",
        "upTheatreBossInfo",
        "onBattleLoadEnd",
        "onTheatrePveEnd",
        "onGoOutBattle",
    }
end

function ClassRef:onEvent(eventName, ...)
    if not self._model:isTheatreMap() then return end

    if eventName == "onMapChanged" then
        self:intoTheatreMap()
    elseif eventName == "onReconnectSuccessed" then
        app:sendMsg("WorldModel", "C2S_RecoveryGameInfo")
    elseif eventName == "upTheatreBossInfo" then
        self._model:updateTheatreBossInfo(...)
    elseif eventName == "onBattleLoadEnd" then
        -- if self._model:isTheatreMap() then
        --     UIHandler:showBlinkBlackScreen()
        -- end
    elseif eventName == "onTheatrePveEnd" then
        UIHandler:showBlinkBlackScreen()
    elseif eventName == "onGoOutBattle" then
        self:_onGoOutBattle()
    end
end

function ClassRef:openView(data)
    if cc.isDead(self._view) then
        self._view = TheatreView.new(app.mvc.VIEWTYPE_NORMAL)
        self._view:onCloseView(handler(self, self.closeView))
        self._view:onClearView(handler(self, self.clearView))
        self._view:onOperate(handler(self, self.onOperate))
        self:addChild(self._view, data)
    end

    self._view:show()
    local info = self._model:getTheatreInfo()
    self._view:refresh(info, BattleManager:isInBattle())
end
function ClassRef:clearView()
    if self._view then
        self._view = nil
    end
end

-- 进入歌剧院地图
function ClassRef:intoTheatreMap()
    local launchCtl = app:getLaunchCtl()
    launchCtl:removeTouchLayer()

    -- 补丁，模拟点击停止移动，其他的方法没找到
    launchCtl:endCharacterMove()

    -- 获取npc
    if not self._npc then
        local npcId = self._model:getNpcId()
        self._npc = NpcManager:getNpcById(npcId)

        local lightAni = cc.CSLoader:createNode(Res.TheatreLightAniNode, true)
        lightAni:setScale(2)
        self._npc:addChild(lightAni)

        MapManager:setFocusCharacterForInit({character=self._npc})
    end

    -- 挂地图切换回调
    local map = MapManager:getMap()
    map:setExitCB(handler(self, self._mapClear))

    -- 不显示对战玩家
    FieldManager:hideMyCharacter()

    if self._model:getTheatreInfo() then
        self:onStartTheatre()
    end
end

function ClassRef:_isEnterTheatreMap()
    return self._model:isTheatreMap() and not MapManager:isChangeMap()
end

-- 设置map默认scale
function ClassRef:_forceCameraToDefault(time, cb)
    local params = {}
    params.time = time or 0
    params.dstScale = MapManager:getDefaultScale()
    params.call = function() executeFunc(cb) end
    MapManager:forceCameraZoomToDest(params)
end

-- 设置map，拉近npc
function ClassRef:_forceCameraToNpc(time, cb)
    local params = {}
    params.time = time or 0
    params.dstScale = 1.3
    params.call = function() executeFunc(cb) end
    MapManager:forceCameraZoomToDest(params)
end

-- 刷新地图上的站立玩家
function ClassRef:_refreshMap()
    UIHandler:getSystemUi():removeAllUI()
    UIHandler:hideDesktop()
    app:sendMsg("IMSimpleController", "showView", Enums.IMSimpleShowType.btn)

    -- 显示对战玩家
    -- if not self._myCharacters then
    --     -- create characters
    --     local myMembers = info.myTeam:getMembers()
    --     local enemyMembers = info.enemyTeam:getMembers()
    --     local posAry = self._model:getMemberPosAry()
    --     self._myCharacters, self._enemyCharacters = 
    --         FieldManager:createTheatreChatacters(myMembers, enemyMembers, posAry)
    -- end

    -- 不显示对战玩家
    FieldManager:hideMyCharacter()

    MapManager:setFocusCharacterForInit({character=self._npc})
end

function ClassRef:_refreshMapBg()
    local info = self._model:getTheatreInfo()
    local map = MapManager:getMap()
    map:updateTheatreBg(info:getTheateBg())
end

function ClassRef:_mapClear()
    -- print("TheatreController._mapClear")
    self._myCharacters = nil
    self._enemyCharacters = nil
    self._npc = nil

    self:_clearResultCronId()

    self._model:clear()

    -- Node still marked as running on node destruction!...
    -- 在node的onExit方法中移除其他的node，可能会报错，parent:addChild
    -- 1. 顺序是 node1 node2 时没问题
    -- 2. 顺序是 node2 node1 时有问题
    -- local parent = app:getLaunchCtl()
    -- local node1 = cc.Node:create()
    -- local node2 = cc.Node:create()
    -- node1:onNodeEvent("exit", function()
    --     print("node1 exit")
    --     node2:removeFromParent()
    -- end)
    -- node2:onNodeEvent("exit", function()
    --     print("node2 exit")
    -- end)
    -- parent:addChild(node2)
    -- parent:addChild(node1)
    -- scheduler.newCron(function()
    --     node1:removeFromParent()
    -- end, 3)

    scheduler.newCron(function()
        self:closeView()
    end, 0)
end

-- npc 说话
-- words        npc说的话 {{word, time}, ...}
-- cb           完成回调
function ClassRef:theatreNpcSpeak(words, cb)
    if not self._npc then return end

    local len = #words
    if len == 0 then 
        executeFunc(cb)
        return 
    end
    
    local idx = 0
    local function showNextBubble()
        idx = idx + 1
        if idx <= len then
            local word = words[idx][1]
            local time = words[idx][2]
            self._npc:showBubble(word, time, function()
                showNextBubble()
            end)
        else
            executeFunc(cb)
        end
    end

    showNextBubble()
end

function ClassRef:_onGoOutBattle()
    self:_clearResultCronId()
    self:_refreshMap()
    if self._sessionResultMsg then
        self:_forceCameraToNpc()

        scheduler.newCron(function()
            if self._sessionResultMsg then
                self:onSessionResult(self._sessionResultMsg)
                self._sessionResultMsg = nil
            end
        end, 0.1)
    else
        -- 战斗结束先来，对局结果还没来
        local info = self._model:getTheatreInfo()
        if info then
            -- 等待歌剧院结果，pvp超时5s之后退出地图
            self._resultCronId = scheduler.newCron(function()
                self._resultCronId = nil
                if info:isLastSession() then
                    -- 最后一场，直接结束
                    self:onTheatreResult({isWon=false, reason="THEATRE_SuperLose"})
                else
                    -- 非最后一场发起actionOver
                    self._model:reqActionOver()
                end
            end, 5)
        else
            -- 没有歌剧院消息，直接退出地图
            self._model:reqBackToMap()
        end
    end
end

function ClassRef:_clearResultCronId()
    if self._resultCronId then
        scheduler.cancelCron(self._resultCronId)
        self._resultCronId = nil
    end
end

-------------------------------------------------------
-- 歌剧院开始
function ClassRef:onStartTheatre()
    -- print("TheatreController.onStartTheatre", self:_isEnterTheatreMap())
    if not self:_isEnterTheatreMap() then return end

    local info = self._model:getTheatreInfo()
    if not info:isLastSession() then
        self:openView()
    end
    self:_refreshMap()
    self:_refreshMapBg()

    -- print("isLoading, isNpcSpeak, isInBattle", info:isLoading(), info:isNpcSpeak(), info:isInBattle())
    if info:isLoading() and not app:sendMsg("PvpModel", "isInPvpLoading") then
        -- 重连／重登时 没有在PvpLoading中，需要向服务器发C2S_PVPLoadingFinish来开启接下来的步骤
        app:sendMsg("PvpModel", "reqFinishLoading", Enums.TeamTarget.theatre)
    elseif info:isNpcSpeak() then
        -- 在npc说话中, cron防止说话泡泡有抖动
        scheduler.newCron(function()
                local words = self._model:getNpcWords(info.sessionID)
                self:theatreNpcSpeak(words, function()
                    self._model:reqActionOver()

                    -- 接下来是选角，设置成默认camera
                    self:_forceCameraToDefault()
                end)
            end, 0.1)
    end

    if info:isInBattle() then
        self:_forceCameraToDefault()
    else
        self:_forceCameraToNpc()
    end
end

-- 加载结束 开始npc对话
function ClassRef:onPvpLoadingClose()
    local info = self._model:getTheatreInfo()
    if not info then return end
    -- print("onPvpLoadingClose", info:isNpcSpeak())
    if info:isNpcSpeak() then
        scheduler.newCron(function()
                local words = self._model:getNpcWords(info.sessionID)
                self:theatreNpcSpeak(words, function()
                    self._model:reqActionOver()

                    -- 接下来是选角，设置成默认camera
                    self:_forceCameraToDefault()
                end)
            end, 0.1)
    end
end

-- 歌剧院对手boss血量更新
function ClassRef:onBossHpUpdate()
    if not self:isViewAlive() then return end

    self._view:updateBossHp()
end

-- 队伍生命数更新
function ClassRef:onTeamLifeUpdate()
    if not self:isViewAlive() then return end

    self._view:updateTeamLife()
end

-- sessionState 更新
function ClassRef:onSessionStateUpdate(state)
    if cc.isDead(self._view) then return end

    -- 选角完毕
    if state == "SessionRoleplayChoosed" then
        self:_forceCameraToDefault()
    elseif state == "SessionBattleStart" then
        self._view:setIsInBattle(true)
    elseif state == "SessionBattleEnd" then
        self._view:setIsInBattle(false)
    end
end

-- 歌剧院pve结果，在动画表现之后再用数据重刷一次界面
function ClassRef:onSessionResult(msg)
    -- 战斗清理还未完成，先缓存数据，等清理完成再执行npc说话
    if BattleManager:isInBattle() then
        self._sessionResultMsg = msg
        return
    end
    self:_clearResultCronId()

    -- 显示对战玩家
    -- local winCharacters = msg.isWon and self._myCharacters or self._enemyCharacters
    -- local failCharacters = msg.isWon and self._enemyCharacters or self._myCharacters
    -- for i,character in ipairs(winCharacters) do
    --     character:play("celebrate")
    -- end
    -- for i,character in ipairs(failCharacters) do
    --     character:play("seriously")
    -- end

    local info = self._model:getTheatreInfo()
    if not info then
        self._model:reqBackToMap()
        release_print("TheatreController.onSessionResult info is nil")
        return
    end

    local sessionID = msg.sessionID
    -- 是否boss胜利
    local isBossWin = msg.failReason == "SESSION_NormalLose"
    local words
    if isBossWin then
        words = self._model:getNpcWords(sessionID, isBossWin, msg.isWon)
    else
        words = self._model:getNpcWords(sessionID, isBossWin, msg.isWon, info:getTeamName())
    end

    self._isInAction = true
    self:theatreNpcSpeak(words, function()
        if isBossWin then
            self:_actionOver()
        else
            if cc.isDead(self._view) then
                self:_actionOver()
                return 
            end

            self._view:playPunishAction(msg, function()
                sessionID = sessionID + 1
                local isLastSession = sessionID == 4
                local cosplayWords = self._model:getNpcCosplayWords(isLastSession, sessionID)
                self:theatreNpcSpeak(cosplayWords, function()
                    self:_actionOver()

                    self:_refreshMapBg()
                    self._model:reqActionOver()

                    -- 选角时，设置默认camera
                    self:_forceCameraToDefault()

                    if not cc.isDead(self._view) then
                        self._view:refresh(self._model:getTheatreInfo(), BattleManager:isInBattle())
                        
                        if isLastSession then
                            self:closeView()
                        end
                    end
                end)
            end)
        end
    end)
end

function ClassRef:_actionOver()
    self._isInAction = false
    if self._theatreResultMsg then
        self:onTheatreResult(self._theatreResultMsg)
        self._theatreResultMsg = nil
    end
end

-- 歌剧院结果
function ClassRef:onTheatreResult(msg)
    -- print("TheatreController.onTheatreResult", self._isInAction)
    if self._isInAction then
        self._theatreResultMsg = msg
        return
    end

    self:_clearResultCronId()

    -- pve阶段即结束了，需要主动退出地图
    if msg.reason == "THEATRE_SuperWin" or 
        msg.reason == "THEATRE_SuperLose" then
        
        local panelName = msg.isWon and "openWinView" or "openFailView"

        -- pvp玩法的回调
        local funcPvp = function()
            MapManager:setNextChangeMapIgnoreAni(true)
            app.session:request("pb_map.C2S_BackToLastMap",{})

            MapManager:setChangeMapOverCB(function()
                app:sendMsg("PvpController", "openView")
            end)
        end 

        app:sendMsg("PvpController", panelName, nil, funcPvp, L(msg.reason))
    end
end

-------------------------------------------------------
function ClassRef:_comfirmEscape()
    local msg = L("lua_code_text_444")
    local confirmDialog = app.mvc.DialogBase.new(msg,
        function()
            self._model:reqEscape()
        end,
        function()

        end)
    confirmDialog:setConfirmText(L("lua_code_text_209"))
    UIHandler:addPopupUi(confirmDialog)
end

function ClassRef:onOperate(op, data)
    -- print("TheatreController:onOperate op", op)
    if op == "escape" then
        self:_comfirmEscape()
    end
end

return ClassRef
